home *** CD-ROM | disk | FTP | other *** search
- // Copyright 1994 by Jon Dart. All Rights Reserved.
-
- #include "scoring.h"
- #include "bearing.h"
- #include "constant.h"
- #include "util.h"
-
- static int RookCenterTable[] =
- {0, 0, 0, 27, 28, 0, 0, 0,
- 0, 0, 0, 27, 28, 0, 0, 0,
- 0, 0, 0, 27, 28, 0, 0, 0,
- 27, 27, 27, 27, 28, 28, 28, 28,
- 35, 35, 35, 35, 36, 36, 36, 36,
- 0, 0, 0, 35, 36, 0, 0, 0,
- 0, 0, 0, 35, 36, 0, 0, 0,
- 0, 0, 0, 35, 36, 0, 0, 0};
-
- static int RookCenterDirs[] =
- {0, 0, 0, 8, 8, 0, 0, 0,
- 0, 0, 0, 8, 8, 0, 0, 0,
- 0, 0, 0, 8, 8, 0, 0, 0,
- 1, 1, 1, 0, 0, -1, -1, -1,
- 1, 1, 1, 0, 0, -1, -1, -1,
- 0, 0, 0, -8, -8, 0, 0, 0,
- 0, 0, 0, -8, -8, 0, 0, 0,
- 0, 0, 0, -8, -8, 0, 0, 0};
-
- static int BishopCenterTable[] =
- {27, 28, 0, 0, 0, 0, 27, 28,
- 35, 27, 28, 0, 0, 27, 28, 36,
- 0, 35, 27, 28, 27, 28, 36, 0,
- 0, 0, 35, 27, 28, 36, 0, 0,
- 0, 0, 27, 28, 36, 28, 0, 0,
- 0, 27, 35, 36, 35, 36, 28, 0,
- 27, 35, 36, 0, 0, 35, 36, 28,
- 35, 36, 0, 0, 0, 0, 35, 36};
-
- static int BishopCenterDirs[] =
- {9, 9, 0, 0, 0, 0, 7, 7,
- 9, 9, 9, 0, 0, 7, 7, 7,
- 0, 9, 9, 9, 7, 7, 7, 0,
- 0, 0, 9, 0, 0, 7, 0, 0,
- 0, 0, -7, 0, 0, -9, 0, 0,
- 0, -7, -7, -7, -9, -9, -9, 0,
- -7, -7, -7, 0, 0, -9, -9, -9,
- -7, -7, 0, 0, 0, 0, -9, -9};
-
- static int KnightCenterScores[] =
- {0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 2, 2, 2, 2, 0, 0,
- 0, 2, 0, 0, 0, 0, 2, 0,
- 0, 2, 0, 5, 5, 0, 2, 0,
- 0, 2, 0, 5, 5, 0, 2, 0,
- 0, 2, 0, 0, 0, 0, 2, 0,
- 0, 0, 2, 2, 2, 2, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0};
-
- static int PawnCenterScores[] =
- {0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 5, 5, 0, 0, 0,
- 0, 0, 4, 6, 6, 4, 0, 0,
- 0, 0, 3, 4, 4, 3, 0, 0,
- 0, 0, -1, -2, -2, -1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0};
-
- static int KingCenterScores[] =
- {0, 0, 1, 1, 1, 1, 0, 0,
- 0, 1, 2, 3, 3, 2, 1, 0,
- 1, 2, 6, 7, 7, 6, 2, 1,
- 1, 3, 7, 9, 9, 7, 3, 1,
- 1, 3, 7, 9, 9, 7, 3, 1,
- 1, 2, 6, 7, 7, 6, 2, 1,
- 0, 1, 2, 3, 3, 2, 1, 0,
- 0, 0, 1, 1, 1, 1, 0, 0};
-
- const int KBNKScores[] =
- {-12, -8, -2, 3, 7, 10, 15, 20,
- -8, -6, 1, 0, 5, 9, 12, 15,
- -2, 1, 0, 0, 5, 8, 9, 10,
- 3, 2, 0, 0, 0, 5, 5, 7,
- 7, 5, 5, 0, 0, 0, 0, 3,
- 10, 9, 8, 5, 0, 0, 1, -2,
- 15, 12, 9, 5, 2, 1, -6, -8,
- 20, 15, 10, 7, 3, -2, -8, -12};
-
- Boolean Scoring::pawn_threats = False;
- int Scoring::en_prise = 0;
- int Scoring::trapped = 0;
-
- static Boolean endgame;
-
- static int distance( const Square sq1, const Square sq2 )
- {
- int file_dist = Util::Abs(sq1.File() - sq2.File());
- int rank_dist = Util::Abs(sq1.Rank(White) - sq2.Rank(White));
- return file_dist + rank_dist;
- }
-
- // Weights for positional scoring components. A plus value means that
- // the item being scored is valuable to the player; a minus value means
- // that a penalty is extracted. In most cases, scoring components are
- // simply summed together to get a total score, but some are folded
- // in, in a more complex way.
-
- // material terms
- const int TWO_BISHOPS = 8;
- // development terms
- const int CENTER1 = 2; // center control by sliding piece
- const int BLOCKED_BISHOP = -4;
- const int LOW_BISHOP_MOBILITY = -2;
- const int BMOBLTHRESH = 3; // threshold before awarding bishop mobility bonus
- const int BISHOP_MOBILITY = 2;
- const int BISHOP_BACK = -6;
- const int CENTER_PAWN_BLOCK = -5; // e or d pawn blocked by piece
- const int LONG_DIAG = 3; // bishop on long diagonal
- const int KNIGHT_BACK = -5;
- const int KNIGHT_ON_RIM = -2;
- const int LOW_ROOK_MOBILITY = -1;
- const int KNIGHT_MOBILITY = 1;
- const int ROOK_ON_7TH_RANK = 5;
- const int QUEEN_DEVELOP = 2;
- const int QUEEN_OUT = -6; // premature development of queen
- const int DOUBLED_ROOKS = 6; // on open file
- const int ROOK_ON_HALF_OPEN_FILE = 2;
- const int ROOK_ON_OPEN_FILE = 2;
- // castling terms
- const int KCASTLE = 9;
- const int QCASTLE = 6;
- const int CAN_CASTLE = -2;
- const int CANT_CASTLE = -12;
- const int CANT_CASTLE_K_SIDE = -6;
- const int CANT_CASTLE_Q_SIDE = -4;
- const int ATTACK_PREVENTS_CASTLING = -3;
- // pawn structure terms
- const int PAWN_ON_7TH_RANK = 4;
- const int BACKWARD_PAWN = -6;
- const int CENTRAL_ISOLANI = -8;
- const int ISOLANI = -6;
- const int DOUBLED_PAWNS = -18;
- const int TRIPLED_PAWNS = -24;
- const int PASSED_PAWN[8] = { 0, 12, 13, 17, 25, 41, 73, 0}; // score by rank
- const int RIM_PASSED_PAWN = -3; // pawn on h-file or a-file
- const int PAWN_DUO = 4; // a la Kmoch
- const int ROOK_BEHIND_PP = 3; // rook or queen behind passed pawn
- const int UNSUPPORTED_PAWN = -1; // an advanced but unsupported pawn
- const int OPP_KING_DISTANCE_FROM_PP = 2; // opposing king distance from passed
- // pawn
- const int OPP_KING_AHEAD_OF_PP = -7;
- // king safety terms
- const int CHECK = -5; // being in check
- const int ATTACK_NEAR_KING = -3; // square near king attacked
- const int KING_OFF_BACK_RANK = -3;
- const int KING_PAWN_COVER = 2;
- const int KING_NEAR_OPEN_FILE = -1;
- const int DANGER_ON_FILE = -2; // rook or queen on file near king
- // king position terms - valid only in endgame
- const int ADVANCED_KING = 4;
- const int KING_NEAR_PAWN = 1;
- const int OPPOSITION = 12;
- const int KING_DISTANCE = 4; // bringing our king closer to bare king
- const int KING_CAN_MOVE = -3; // for each square opposing bare king can move
- const int KING_ON_EDGE = 4; // opposing king on edge
- const int KING_IN_CORNER = 4; // opposing king in corner
- // piece safety terms
- const int EN_PRISE = -6; // piece apparently hung
- const int PIECE_TRAPPED = -6; // piece apparently trapped
- const int TWO_EN_PRISE = -10; // >1 piece apparently hung
- // general endgame terms
- const int KING_PAWN_DISTANCE = -10; // distance from opposing king
- const int OPP_KING_AHEAD_OF_PAWN = 8;
- // KP vs. K endgame
- const int UNCATCHABLE_PAWN = 450;
- const int KING_AHEAD_OF_PAWN = 32;
- const int KING_SAME_FILE = 32;
- const int DISTANCE_FROM_PAWN = -8;
-
- static int MaterialScore( const Board &board, const ColorType side )
- {
- // Computes material score, from the perspective of 'side'.
- // Algorithm is based on that used by Chess 4.5.
- unsigned long ourmat, oppmat, totmat;
- int mdiff;
-
- ourmat = board.getMaterial(side).value();
- oppmat = board.getMaterial(OppositeColor(side)).value();
- mdiff = (int)(ourmat - oppmat);
- if (Util::Abs(mdiff) > 2*Constants::PawnValue)
- {
- totmat = ourmat + oppmat;
- return mdiff + (Util::Sign(mdiff)*( (10240L - totmat) /
- Constants::PawnValue ));
- }
- else
- return mdiff;
- }
-
- static Boolean in_endgame( const Board &board, const ColorType side )
- {
- return Boolean((board.getMaterial(side).value()
- <= Piece::Value(Piece::King) +
- Piece::Value(Piece::Queen)) &&
- (board.getMaterial(OppositeColor(side)).value() <=
- Piece::Value(Piece::King) + Piece::Value(Piece::Queen) +
- 2*Piece::Value(Piece::Pawn)));
- }
-
- static Boolean mopping_up( const Board &board, const ColorType side )
- {
- // Returns "true" if "side" has great material advantage (probably
- // enough to mate by force)
-
- const Material &my_mat = board.getMaterial(side);
- const Material &opp_mat = board.getMaterial(OppositeColor(side));
-
- if (opp_mat.king_only() && !endgame)
- return True;
- else if (my_mat.value() - opp_mat.value() < 570)
- return False;
- else
- return (my_mat.value() + opp_mat.value() < 5000);
- }
-
- int Center( const Board &board, const ColorType side)
- {
- if (endgame)
- {
- if (mopping_up(board,OppositeColor(side)))
- return KingCenterScores[board.KingPos(side)];
- else
- return 0;
- }
- int score = 0;
- Square target;
- for (int i = 0; i < 16; i++)
- {
- Square sq(board.PiecePos(side,i));
- if (!sq.IsInvalid())
- {
- Piece piece = board[sq];
- switch (piece.Type())
- {
- case Piece::Pawn:
- if (side == White)
- score += PawnCenterScores[sq];
- else
- score += PawnCenterScores[63-(int)sq];
- break;
- case Piece::Knight:
- score += KnightCenterScores[sq];
- break;
- case Piece::Bishop:
- target = Square(BishopCenterTable[sq]);
- if (target)
- {
- int dir = BishopCenterDirs[sq];
- if (dir)
- {
- for (;;)
- {
- sq += dir;
- if (sq == target)
- {
- score += CENTER1;
- break;
- }
- else if (!board[sq].IsEmpty())
- break;
- }
- }
- else
- score += CENTER1;
- }
- break;
- case Piece::Rook:
- target = Square(RookCenterTable[sq]);
- if (target)
- {
- int dir = RookCenterDirs[sq];
- if (dir)
- {
- for (;;)
- {
- sq += dir;
- if (sq == target)
- {
- score += CENTER1;
- break;
- }
- else if (!board[sq].IsEmpty())
- break;
- }
- }
- else
- score += CENTER1;
- }
- break;
- case Piece::Queen:
- target = Square(BishopCenterTable[sq]);
- if (target)
- {
- int dir = BishopCenterDirs[sq];
- if (dir)
- {
- for (;;)
- {
- sq += dir;
- if (sq == target)
- {
- score += CENTER1;
- break;
- }
- else if (!board[sq].IsEmpty())
- break;
- }
- }
- else
- score += CENTER1;
- }
-
- target = Square(RookCenterTable[sq]);
- if (target)
- {
- int dir = RookCenterDirs[sq];
- if (dir)
- {
- for (;;)
- {
- sq += dir;
- if (sq == target)
- {
- score += CENTER1;
- break;
- }
- else if (!board[sq].IsEmpty())
- break;
- }
- }
- else
- score += CENTER1;
- }
- break;
- default:
- break;
- }
- }
- }
- return score;
- }
-
- int Development( const Board &board, const ColorType side)
- // development of pieces
- {
- int score = 0;
- int score2 = 0;
- int mobl = 0;
- Boolean have_queen = False;
- Boolean queen_back = False;
- const ColorType oside = OppositeColor(side);
- const Material &my_mat = board.getMaterial(side);
- if (my_mat.count(Piece::Bishop) >= 2)
- score += TWO_BISHOPS;
- for (int i = 0; i < 16; i++)
- {
- Square sq(board.PiecePos(side,i));
- if (!sq.IsInvalid())
- {
- Piece piece = board[sq];
- if (piece.Type() != Piece::Pawn)
- {
- const int rank = sq.Rank(side);
- const int file = sq.File();
- Boolean back = Boolean(rank == 1);
- if (!endgame)
- {
- if ((rank == 3 || rank == 4) &&
- (file == 4 || file == 5))
- {
- int incr = 8*Direction[side];
- if (board[sq-incr].Type() == Piece::Pawn ||
- board[sq-2*incr].Type() == Piece::Pawn)
- score += CENTER_PAWN_BLOCK;
- }
- }
- switch(piece.Type())
- {
- case Piece::Bishop:
- {
- {
- for (int j = 0; j < 4; j++)
- {
- const byte *data = BishopSquares[sq] + (j*8);
- for (;;)
- {
- byte b = *data;
- if (b == 255)
- break;
- data++;
- Piece piece = board[b];
- if (piece.IsEmpty())
- mobl++;
- else
- break;
- }
- }
- }
- if (mobl==0)
- score2 += BLOCKED_BISHOP;
- else if (mobl == 1)
- score2 += LOW_BISHOP_MOBILITY;
- else if (mobl > BMOBLTHRESH)
- score2 += (mobl / BMOBLTHRESH)*BISHOP_MOBILITY;
- if (rank == file)
- score2 += LONG_DIAG;
- if (back && !endgame)
- score += BISHOP_BACK;
- }
- break;
- case Piece::Knight:
- if (back && !endgame)
- score += KNIGHT_BACK;
- if (file == 1 || file == 8)
- score2 += KNIGHT_ON_RIM;
- if (!endgame)
- {
- const byte *data = KnightSquares[(int)sq];
- int j = 0;
- while (j < 8 && data[j] != 255)
- {
- Square dest(data[j]);
- if (board[dest].IsEmpty() &&
- board.pawn_attacks(dest,oside) ==0)
- score += KNIGHT_MOBILITY;
- ++j;
- }
- }
- break;
- case Piece::Queen:
- have_queen = True;
- queen_back = back;
- break;
- case Piece::Rook:
- if (back && !endgame)
- {
- mobl = 0;
- Square sq2(sq);
- while (sq2.File() < 8)
- {
- ++sq2;
- if (board[sq2].IsEmpty())
- mobl++;
- else
- break;
- }
- sq2 = sq;
- while (sq2.File() > 1)
- {
- --sq2;
- if (board[sq2].IsEmpty())
- mobl++;
- else
- break;
- }
- if (mobl < 3)
- score2 += LOW_ROOK_MOBILITY;
- }
- if (rank == 7)
- score2 += ROOK_ON_7TH_RANK;
- if (board.PFileCount(file-1,side)==0)
- score2 += ROOK_ON_HALF_OPEN_FILE;
- if (board.PFileCount(file-1,oside)==0)
- {
- score2 += ROOK_ON_OPEN_FILE;
- const int rr = board.RFileCount(file-1,side);
- if (rr>=2)
- score2 += DOUBLED_ROOKS/2;
- }
- default:
- break;
- }
- }
- }
- }
- if (!endgame && have_queen && !queen_back)
- {
- if (score == 0 &&
- (board.CastleStatus(side) == Board::CastledKSide ||
- board.CastleStatus(side) == Board::CastledQSide))
- score += QUEEN_DEVELOP;
- else // premature development of queen
- score += QUEEN_OUT;
- }
- if (endgame)
- {
- Square kp(board.KingPos(side));
- if (board.Side() != side)
- {
- for (int j = 0; j < 4; j++)
- {
- const byte *data = RookSquares[kp] + (j*8);
- if (*data == 255)
- continue;
- else
- data++;
- if (*data != 255 && board[*data].Type() == Piece::King)
- {
- score += OPPOSITION;
- break;
- }
- }
- }
- if (mopping_up(board,side))
- {
- // Encourage bringing our king close to opposing king:
- Square oppkp(board.KingPos(oside));
- const int opprank = oppkp.Rank(White);
- const int oppfile = oppkp.File();
- const int ourrank = kp.Rank(White);
- const int ourfile = kp.File();
- int dist = Util::Abs(oppfile - ourfile) +
- Util::Abs(ourrank - opprank);
- score += (5-dist)*KING_DISTANCE;
- if ((unsigned)board.getMaterial(side).infobits() == 0x8048)
- {
- // KBNK endgame, special case. This code is currently
- // insufficient to allow the stronger side to win, but
- // it does help the weaker side put up a good defense.
- ColorType bishopColor;
- for (int i = 0; i < 16; i++)
- {
- Square sq(board.PiecePos(board.Side(),i));
- if ( sq != Square::Invalid())
- if (board[sq].Type() == Piece::Bishop)
- {
- bishopColor = sq.Color();
- break;
- }
- }
- // encourage getting the king to the "right" corner:
- Square evalsq;
- if (bishopColor == White)
- {
- evalsq = Square(9-opprank, oppfile, White);
- }
- else
- {
- evalsq = oppkp;
- }
- score += KBNKScores[evalsq];
- }
- else
- {
- // Encourage putting the king on the edge of the board:
- if (oppkp.OnEdge())
- score += KING_ON_EDGE;
- if (oppfile == 1 || oppfile == 8)
- {
- if (opprank == 1 || opprank == 8)
- score += KING_IN_CORNER;
- }
- // Encourage restricting opposing king's mobility:
- const byte *data = KingSquares[(int)oppkp];
- score -= 8*KING_CAN_MOVE;
- for (i = 0; i <8 && *data != 255 ;i++)
- {
- Square sq(*data++);
- if (board.num_attacks(sq,side) == 0)
- score += KING_CAN_MOVE;
- }
- }
- }
- else if ((unsigned)board.getMaterial(side).infobits() == 0x8001 &&
- (unsigned)board.getMaterial(oside).king_only())
- {
- // KPK endgame
- Square pawnpos;
- for (int i = 0; i < 16; i++)
- {
- Square sq(board.PiecePos(side,i));
- if (!sq.IsInvalid() && board[sq].Type() == Piece::Pawn)
- {
- pawnpos = sq;
- break;
- }
- }
- Square oppkp(board.KingPos(oside));
- Square kp(board.KingPos(side));
- Boolean uncatchable = False;
- if (board.Side() == side)
- {
- uncatchable =
- (pawnpos.Rank(side) >= oppkp.Rank(side) &&
- Util::Abs(pawnpos.File() - oppkp.File()) >=
- 8 - pawnpos.Rank(side));
- }
- else
- {
- uncatchable =
- (pawnpos.Rank(side) >= oppkp.Rank(side) + 1 &&
- Util::Abs(pawnpos.File() - oppkp.File()) >=
- 9 - pawnpos.Rank(side));
- }
- if (uncatchable)
- score += UNCATCHABLE_PAWN;
- else
- {
- // we can't just push the pawn.
- int rank = pawnpos.Rank(side);
- int file_dist = Util::Abs(pawnpos.File() - kp.File());
- if (kp.Rank(side) > rank && file_dist <= 1)
- {
- score += KING_AHEAD_OF_PAWN;
- if (rank < 6 && file_dist == 0)
- score += KING_SAME_FILE;
- }
- else
- score -= PASSED_PAWN[rank-1]/2;
- // also encourage staying near pawn
- score += 10 + DISTANCE_FROM_PAWN*distance(kp,pawnpos);
- }
- }
- else
- {
- // This code is VERY crude .. it helps (a little) in king and
- // pawn endgames, but is pretty useless otherwise ... Lots more
- // work to do here.
- score += KingCenterScores[kp];
- if (kp.Rank(side) > 4)
- score += ADVANCED_KING;
- // bonus for king near pawns
- const byte *data = KingSquares[(int)kp];
- const Boolean king_only
- = (unsigned)board.getMaterial(side).king_only();
- for (i = 0; i <8 && *data != 255 ;i++)
- {
- Square sq(*data++);
- if (board[sq].Type() == Piece::Pawn)
- {
- score += KING_NEAR_PAWN;
- if (king_only)
- {
- int file_dist = Util::Abs(kp.File() - sq.File());
- int rank_dist = Util::Abs(kp.Rank(side) - sq.Rank(side));
- score += 20 + KING_PAWN_DISTANCE*(file_dist + rank_dist);
- if (kp.Rank(oside) >
- sq.Rank(oside))
- score += OPP_KING_AHEAD_OF_PAWN;
- }
- }
- }
- }
-
- }
- return score + score2;
- }
-
- Boolean search( const Board &board, const Square &sq,
- const int start, const int limit, const ColorType side_to_search,
- const ColorType side )
- {
- // search rows adjacent to "sq" for presence of a pawn of color
- // 'side_to_search'.
- // search covers ranks "start" to "limit" (from the perspective of
- // 'side'). The function value is set True if a pawn is found.
-
- const Piece apawn(Piece::Pawn,side_to_search);
-
- int dir, incr;
- if (limit > start)
- {
- dir = 1;
- incr = RankIncr;
- }
- else
- {
- dir = -1;
- incr = -RankIncr;
- }
- if (side == White) incr = -incr;
-
- const int file = sq.File();
- Square sq2(file,start,side);
-
- for (int rank = start; rank != limit; rank += dir)
- {
- if (((file != 8) && board[sq2 + 1] == apawn) ||
- ((file != 1) && board[sq2 - 1] == apawn))
- return True;
- sq2 += incr;
- }
- return False;
- }
-
- int PawnStructure( const Board &board, const ColorType side )
- {
- int score = 0;
- const Piece our_pawn( Piece::Pawn, side );
- for (int k = 0; k < 16; k++)
- {
- Square sq(board.PiecePos(side,k));
- if (!sq.IsInvalid())
- {
- Piece piece = board[sq];
- if (piece.Type() == Piece::Pawn)
- {
- int rank = sq.Rank(side);
- int file = sq.File();
- Boolean backward = False;
- Boolean passed = False;
- Boolean isolated;
- if (rank == 7)
- score += PAWN_ON_7TH_RANK;
- if (board.PFileCount(file-1,OppositeColor(side))==0)
- {
- backward = !search(board,sq,rank,1,side,side);
- passed = !search(board,sq,rank+1,8,OppositeColor(side),side);
- }
- isolated = Boolean(board.PFileCount(file-1,side)==0 &&
- board.PFileCount(file+1,side)==0);
- if (backward && !isolated)
- score += BACKWARD_PAWN;
- else if (isolated)
- {
- if (file>=3 && file<=6)
- score += CENTRAL_ISOLANI;
- else
- score += ISOLANI;
- }
- if (!isolated && rank > 2)
- {
- Square sq2 = sq + ((Direction[side] >0) ?
- -RankIncr : +RankIncr);
- if (!(file != 1 && board[sq2 - 1] == our_pawn) &&
- !(file != 8 && board[sq2 + 1] == our_pawn))
- score += UNSUPPORTED_PAWN;
- }
- if (passed)
- {
- score += PASSED_PAWN[rank-1];
- if (file ==1 || file == 8)
- score += RIM_PASSED_PAWN;
- for (int j=rank+1;j<9;j++)
- {
- Square sq2(file,j,side);
- Piece piece2 = board[sq2];
- if (!piece2.IsEmpty() &&
- (piece2.Color() == OppositeColor(side)))
- {
- // blocked passed pawn
- int hit = PASSED_PAWN[rank-1]/3;
- // double score if we block the passed pawn
- // by occupying the square in front of it:
- if (j==rank+1)
- score -= 2*hit;
- else
- score -= hit;
- break;
- }
- }
- if (endgame)
- {
- Square oppkp(board.KingPos(OppositeColor(side)));
- score += OPP_KING_DISTANCE_FROM_PP*
- distance(oppkp,sq);
- if (oppkp.Rank(side) > sq.Rank(side))
- score += OPP_KING_AHEAD_OF_PP;
- }
- for (j=rank-1;j>0;j--)
- {
- Square sq3(file,j,side);
- Piece piece3 = board[sq3];
- if (!piece3.IsEmpty())
- {
- if (piece3.Color() == side)
- {
- if (piece3.Type() == Piece::Rook || piece3.Type()
- == Piece::Queen)
- {
- score += ROOK_BEHIND_PP;
- break;
- }
- }
- else
- break;
- }
- }
- }
- if (rank >3 && file != 8 && board[sq+1] == piece)
- score += PAWN_DUO;
- }
- }
- }
- for (int i = 0; i < 8; i++)
- {
- const int pr = board.PFileCount(i,side);
- if (pr == 2)
- score += DOUBLED_PAWNS;
- else if (pr > 2)
- score += TRIPLED_PAWNS;
- }
- return score;
- }
-
- int Castling( const Board &board, const ColorType side )
- {
- int score = 0;
- int i;
- int atcks = 0;
- Square kp(board.KingPos(side));
- switch (board.CastleStatus(side))
- {
- case Board::CanCastleEitherSide:
- score += CAN_CASTLE;
- for (i = -1; i >= -2; --i)
- if (board.num_attacks(kp+i,OppositeColor(side)))
- {
- atcks++;
- break;
- }
- for (i = 1; i <= 2; ++i)
- if (board.num_attacks(kp+i,OppositeColor(side)))
- {
- atcks++;
- break;
- }
- score += (ATTACK_PREVENTS_CASTLING)*atcks;
- break;
- case Board::CanCastleKSide:
- score += CANT_CASTLE_Q_SIDE;
- for (i = 1; i <= 2; ++i)
- if (board.num_attacks(kp+i,OppositeColor(side)))
- {
- atcks++;
- break;
- }
- if (atcks)
- score += (ATTACK_PREVENTS_CASTLING)*atcks;
- break;
- case Board::CanCastleQSide:
- score += CANT_CASTLE_K_SIDE;
- for (i = -1; i >= -2; --i)
- if (board.num_attacks(kp+i,OppositeColor(side)))
- {
- atcks++;
- break;
- }
- if (atcks)
- score += ATTACK_PREVENTS_CASTLING;
- break;
- case Board::CastledKSide:
- score += KCASTLE; break;
- case Board::CastledQSide:
- score += QCASTLE; break;
- case Board::CantCastleEitherSide:
- score += CANT_CASTLE; break;
- }
- return score;
- }
-
- int KingSafety( const Board &board, const ColorType side)
- {
- int score = 0;
- if ((side == board.Side()) && board.CheckStatus() == Board::InCheck)
- score += CHECK;
- Square kp(board.KingPos(side));
- if (!endgame || mopping_up(board,OppositeColor(side)))
- {
- const byte *data = KingSquares[(int)kp];
- for (int i = 0; i <8 && *data != 255 ;i++)
- {
- if (board.num_attacks(*data++,OppositeColor(side)) >0)
- score += ATTACK_NEAR_KING;
- }
- }
- if (!endgame)
- {
- if (kp.Rank(side) != 8)
- score += KING_OFF_BACK_RANK;
- int dir = (side == White ? -RankIncr : RankIncr);
- Piece my_pawn(Piece::Pawn,side);
- if (kp.File() != 1)
- {
- Square sq(kp-1);
- Square pawnsq(sq+dir);
- if (pawnsq.OnBoard() &&
- board[pawnsq] == my_pawn)
- score += KING_PAWN_COVER;
- else if (board.PFileCount(sq.File()-1,side) == 0 &&
- board.PFileCount(sq.File()-1,OppositeColor(side)) == 0)
- score += KING_NEAR_OPEN_FILE;
- }
- Square pawnsq(kp+dir);
- if (pawnsq.OnBoard() &&
- board[pawnsq] == my_pawn)
- score += KING_PAWN_COVER;
- else if (board.PFileCount(kp.File()-1,side) == 0 &&
- board.PFileCount(kp.File()-1,OppositeColor(side)) == 0)
- score += KING_NEAR_OPEN_FILE;
- if (kp.File() != 8)
- {
- Square sq(kp+1);
- Square pawnsq(sq+dir);
- if (pawnsq.OnBoard() &&
- board[pawnsq] == my_pawn)
- score += KING_PAWN_COVER;
- else if (board.PFileCount(sq.File()-1,side) == 0 &&
- board.PFileCount(sq.File()-1,OppositeColor(side)) == 0)
- score += KING_NEAR_OPEN_FILE;
- }
- const int kpfile = kp.File();
- for (int j=0;j<16;j++)
- {
- Square sq(board.PiecePos(board.OppositeSide(),j));
- if (!sq.IsInvalid())
- {
- Piece::PieceType p = board[sq].Type();
- if (p==Piece::Rook || p == Piece::Queen)
- {
- if (Util::Abs(kpfile - sq.File()) <= 1)
- {
- score += DANGER_ON_FILE;
- break;
- }
- }
- }
- }
- }
- return score;
- }
-
- Boolean Scoring::check_en_prise( const Board &board, const Square sq,
- const Piece p)
- {
- Boolean en_prise = False;
- if (p.Type() == Piece::Pawn ||
- board.num_attacks(sq,board.OppositeSide()) == 0)
- {
- return False;
- }
- if (board.pawn_attacks(sq,board.OppositeSide()) > 0)
- {
- Scoring::pawn_threats = en_prise = True;
- }
- else if (board.num_attacks(sq,board.Side()) == 0)
- en_prise = True;
- else
- {
- const Attack_Entry &entr =
- board.get_attacks(sq,board.OppositeSide());
- if (Piece::Value(entr.min_attacker()) < p.Value())
- en_prise = True;
- }
- return en_prise;
- }
-
- int Scoring::threat_score( const Board &board, const ColorType side )
- {
- int score = 0;
- en_prise = 0;
- trapped = False;
- pawn_threats = False;
- for (int i = 0; i < 16; i++)
- {
- Square sq(board.PiecePos(side,i));
- if (!sq.IsInvalid())
- {
- Piece piece(board[sq]);
- if (check_en_prise(board,sq,piece))
- {
- // piece is apparently en prise
- score += EN_PRISE;
- en_prise++;
- if (!trapped)
- {
- trapped = True;
- Piece pinnedByPiece;
- Square pinnedBySquare;
- int dir;
- Boolean pinned =
- Bearing::Pinned(board,sq,pinnedByPiece,
- pinnedBySquare,dir);
- // Treat a pinned piece same as a trapped one:
- if (pinned)
- continue;
- Square squares[Bearing::MaxBearSq];
- unsigned n = Bearing::BearSq(board,sq,squares);
- for (unsigned j = 0; j < n; j++)
- {
- Square dest(squares[j]);
- if (!check_en_prise(board,dest,piece))
- {
- trapped = False;
- break;
- }
- } // for
- }
- }
- }
- }
- if (en_prise > 1)
- score += TWO_EN_PRISE;
- if (trapped)
- score += PIECE_TRAPPED;
- return score;
- }
-
- int Scoring::evalu8( const Board &board )
- {
- int score = 0;
- endgame = in_endgame(board,board.Side());
- score += MaterialScore(board,board.Side())
- + Center(board,board.Side())
- - Center(board,board.OppositeSide())
- + Development(board,board.Side())
- - Development(board,board.OppositeSide())
- + Castling(board,board.Side())
- - Castling(board,board.OppositeSide())
- + PawnStructure(board,board.Side())
- - PawnStructure(board,board.OppositeSide())
- + KingSafety(board,board.Side())
- - KingSafety(board,board.OppositeSide())
- + threat_score(board,board.Side());
-
- return score;
- }
-
- int Scoring::positional_score( const Board &board )
- // returns a positional score
- {
- int score = 0;
- endgame = in_endgame(board,board.Side());
- score += Center(board,board.Side())
- - Center(board,board.OppositeSide())
- + Development(board,board.Side())
- - Development(board,board.OppositeSide())
- + Castling(board,board.Side())
- - Castling(board,board.OppositeSide())
- + PawnStructure(board,board.Side())
- - PawnStructure(board,board.OppositeSide())
- + KingSafety(board,board.Side())
- - KingSafety(board,board.OppositeSide())
- + threat_score(board,board.Side());
-
- return score;
- }
-
- int Scoring::positional_score( const Board &board, Scores &scores,
- Scores &opp_scores )
- // returns a positional score
- {
- endgame = in_endgame(board,board.Side());
- scores.center = Center(board,board.Side());
- opp_scores.center = Center(board,board.OppositeSide());
- scores.development =
- Development(board,board.Side());
- opp_scores.development =
- Development(board,board.OppositeSide());
- scores.castling =
- Castling(board,board.Side());
- opp_scores.castling =
- Castling(board,board.OppositeSide());
- scores.pawn_structure =
- PawnStructure(board,board.Side());
- opp_scores.pawn_structure =
- PawnStructure(board,board.OppositeSide());
- scores.king_safety =
- KingSafety(board,board.Side());
- opp_scores.king_safety =
- KingSafety(board,board.OppositeSide());
- scores.threats =
- threat_score(board,board.Side());
- opp_scores.threats = 0;
-
- return scores.center + scores.development + scores.castling +
- scores.pawn_structure + scores.king_safety + scores.threats
- - (opp_scores.center + opp_scores.development +
- opp_scores.castling + opp_scores.pawn_structure +
- opp_scores.king_safety + opp_scores.threats);
- }
-
- int Scoring::material_score( const Board &board )
- // returns a material score
- {
- return MaterialScore(board,board.Side());
- }
-